﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Media.Media3D; // PresentationCore Assemblymust be added

namespace PlanetsAndOrbs
{
    public abstract class World : Object3D
    {
        public override double distance(Vector3D origin, Vector3D direction)
        {
            return 1e10f;   // in the far galaxy
        }
    }

    public class ColorWorld : World
    {
        private Vector3D vSkyColor_, vHorizontColor_;

        public ColorWorld(Color sky, Color horizont)
        {
            vSkyColor_ = PixelRenderer.color2V3D(sky);
            vHorizontColor_ = PixelRenderer.color2V3D(horizont);
        }

        public override bool trace(ref Vector3D origin, ref Vector3D ray, out Vector3D filter, out Vector3D emission)
        {
            filter = new Vector3D();
            double alpha = Math.Abs(ray.Y);
            emission = vSkyColor_ * alpha + vHorizontColor_ * (1 - alpha);
            return true;
        }
    }

    public class ImageWorld : World
    {
        private Bitmap skyImage_;

        public ImageWorld(Bitmap skyImage)
        {
            skyImage_ = skyImage;
        }

        public override bool trace(ref Vector3D origin, ref Vector3D ray, out Vector3D filter, out Vector3D emission)
        {
            filter = new Vector3D();

            if (ray.Y <= 0)
            {
                emission = new Vector3D();
                return true;
            }

            int elevation = (int)((skyImage_.Height - 1) * (1 - ray.Y));

            Vector3D radius = new Vector3D(ray.X, 0, ray.Z);
            radius.Normalize();
            double a;
            if (Math.Abs(radius.X) < Math.Abs(radius.Z)) 
            {
                a = Math.Asin(radius.X) / Math.PI / 2; // -0.25 .. 0.25
                if (radius.Z > 0)
                    a += 0.5;   // middle
                else
                    a = radius.X < 0 ? -a : 1 - a;
            }
            else
            {
                a = Math.Asin(radius.Z) / Math.PI / 2;
                a = radius.X < 0 ? 0.25 + a : 0.75 - a; 
            }
            
            int asimuth = (int)((skyImage_.Width - 1) * a);
            emission = PixelRenderer.color2V3D(skyImage_.GetPixel(asimuth, elevation));
            return true;
        }
    }
}
